package com.yunji.base.event;

import com.google.common.collect.Lists;
import com.google.common.eventbus.Subscribe;
import com.yunji.base.cache.BaseCache;
import com.yunji.base.domain.BelongDO;
import com.yunji.common.enums.common.MessageTypes;
import com.yunji.common.enums.common.NoticeTypes;
import com.yunji.base.service.BelongService;
import com.yunji.base.service.StaffService;
import com.yunji.cabinet.bo.CabinetCellListQueryBO;
import com.yunji.cabinet.cache.CabinetCache;
import com.yunji.cabinet.domain.ContainerCell;
import com.yunji.cabinet.domain.ContainerDO;
import com.yunji.cabinet.domain.CabinetSiteDO;
import com.yunji.cabinet.service.ICabinetCellService;
import com.yunji.cabinet.service.ICabinetService;
import com.yunji.common.enums.common.UserType;
import com.yunji.common.event.notice.*;
import com.yunji.common.model.cache.CabinetCacheDTO;
import com.yunji.common.model.cache.ProductCacheDTO;
import com.yunji.common.model.domain.*;
import com.yunji.common.model.dto.*;
import com.yunji.common.model.enums.LoginTypeEnum;
import com.yunji.common.utils.ConvertDataUtil;
import com.yunji.common.utils.JsonUtil;
import com.yunji.common.utils.StringUtils;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.order.domain.OrderDO;
import com.yunji.order.domain.OrderDetailDO;
import com.yunji.order.service.OrderService;
import com.yunji.product.cache.ProductCache;
import com.yunji.system.service.NoticeService;
import com.yunji.system.service.NoticeUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;

import static com.yunji.common.enums.common.NoticeTypes.*;

@Slf4j
@Component
public class NoticeListener {

    @Resource
    ICabinetCellService cabinetCellService;

    @Resource
    ICabinetService cabinetService;

    @Resource
    StaffService staffService;

    @Resource
    NoticeService noticeService;

    @Resource
    NoticeUserService noticeUserService;

    @Resource
    BelongService belongService;

    @Resource
    OrderService orderService;

    @Subscribe
    public void LowBattleNoticeEvent(LowBattleNoticeEvent event) {
        // 传员工belongId
        List<String> imeiList = event.getImeiList();

        for (String imei : imeiList) {
            CabinetCacheDTO cabinet = CabinetCache.getCabinet(imei);
            Long belongId = cabinet.getBelongId();
            if (belongId == null) {continue;}
            String siteName = BaseCache.getSiteName(cabinet.getSiteId());
            LowBattleDTO lowBattleDTO = new LowBattleDTO();
            lowBattleDTO.setNoticeType(LOW_BATTLE.getText());
            lowBattleDTO.setNoticeTitle(LOW_BATTLE.getTitle());
            lowBattleDTO.setNoticeContent(StringUtils.format(LOW_BATTLE.getTemplate(),siteName,cabinet.getContainerName()));
            dispenseNotice(LOW_BATTLE.getCode(),JsonUtil.toJsonString(lowBattleDTO),LoginTypeEnum.STAFF.name(), belongId);

        }
    }

    @Subscribe
    public void InfraredWarmNoticeEvent(InfraredWarmNoticeEvent event) {
        // 传员工belongId
        // 传员工belongId
        List<String> imeiList = event.getImeiList();

        for (String imei : imeiList) {
            CabinetCacheDTO cabinet = CabinetCache.getCabinet(imei);
            Long belongId = cabinet.getBelongId();
            if (belongId == null) {continue;}
            String siteName = BaseCache.getSiteName(cabinet.getSiteId());
            LowBattleDTO lowBattleDTO = new LowBattleDTO();
            lowBattleDTO.setNoticeType(ABNORMAL_DEVICE_WARM.getText());
            lowBattleDTO.setNoticeTitle(ABNORMAL_DEVICE_WARM.getTitle());
            lowBattleDTO.setNoticeContent(StringUtils.format(ABNORMAL_DEVICE_WARM.getTemplate(),siteName,cabinet.getContainerName()));
            dispenseNotice(ABNORMAL_DEVICE_WARM.getCode(),JsonUtil.toJsonString(lowBattleDTO),LoginTypeEnum.STAFF.name(), belongId);

        }
    }

    @Subscribe
    public void StockWarmNoticeEvent(StockWarmNoticeEvent event) {
        Long productId = event.getProductId();
        LoginInfo loginInfo = event.getLoginInfo();

        StockWarmDTO stockWarmDTO = new StockWarmDTO();
        stockWarmDTO.setNoticeType(STOCK_WARM.getText());
        stockWarmDTO.setNoticeTitle(STOCK_WARM.getTitle());
        stockWarmDTO.setNoticeContent(StringUtils.format(NoticeTypes.STOCK_WARM.getTemplate(),BaseCache.getBelongName(loginInfo.getBelongId()),ProductCache.getProductName(productId)));

        dispenseNotice(STOCK_WARM.getCode(), JsonUtil.toJsonString(stockWarmDTO),loginInfo.getLoginType().name(),loginInfo.getBelongId());

    }

    @Subscribe
    public void NoCargoNoticeEvent(NoCargoNoticeEvent event) {
        Long containerId = event.getContainerId();

        ContainerDO cabinet = cabinetService.getById(containerId);

        NoCargoDTO noCargoDTO = new NoCargoDTO();
        noCargoDTO.setNoticeType(NO_CARGO.getText());
        noCargoDTO.setNoticeTitle(NO_CARGO.getTitle());
        noCargoDTO.setNoticeContent(StringUtils.format(NO_CARGO.getTemplate(),BaseCache.getSiteName(cabinet.getSiteId()),cabinet.getContainerName()));

        dispenseNotice(NO_CARGO.getCode(), JsonUtil.toJsonString(noCargoDTO),LoginTypeEnum.CUSTOMER.name(), cabinet.getBelongId());
    }

    @Subscribe
    public void LackCargoNoticeEvent(LackCargoNoticeEvent event) {
        Long containerId = event.getContainerId();

        ContainerDO cabinet = cabinetService.getById(containerId);

        LackCargoDTO lackCargoDTO = new LackCargoDTO();
        lackCargoDTO.setNoticeType(NO_CARGO.getText());
        lackCargoDTO.setNoticeTitle(NO_CARGO.getTitle());
        lackCargoDTO.setNoticeContent(StringUtils.format(NO_CARGO.getTemplate(),BaseCache.getSiteName(cabinet.getSiteId()),cabinet.getContainerName()));

        dispenseNotice(NO_CARGO.getCode(), JsonUtil.toJsonString(lackCargoDTO),LoginTypeEnum.CUSTOMER.name(), cabinet.getBelongId());
    }

    @Subscribe
    public void SellPriceNoticeEvent(SellProductNoticeEvent event){
        Long orderId = event.getOrderId();
        OrderDO order = orderService.getOrderById(orderId);

        SellProductDTO sellProductDTO = new SellProductDTO();
        BeanUtils.clone(order, sellProductDTO);
        sellProductDTO.setNoticeTitle(SELL_PRODUCT.getTitle());
        List<Integer> ordinals = orderService.getOrdinalsByOrderId(orderId);
        List<String> names = orderService.getOrderNamesByOrderId(orderId);
        sellProductDTO.setNoticeContent(StringUtils.format(SELL_PRODUCT.getTemplate(),
                ordinals.toString().replace("[","").replace("]",""),
                names.toString().replace("[","").replace("]","")));
        //找到有商品的格子
        List<ContainerCell> cells = cabinetCellService.search(CabinetCellListQueryBO.builder().containerId(order.getContainerId()).build());
        List<NoticeDataCellDTO> cellList = new ArrayList<>();
        for (ContainerCell cell : cells) {
            NoticeDataCellDTO cellDTO = new NoticeDataCellDTO();
            BeanUtils.clone(cell, cellDTO);
            ProductCacheDTO product = ProductCache.getProduct(cell.getProductId());
            cellDTO.setAlbumPics(product.getAlbumPics());
            cellDTO.setProductName(ProductCache.getProductName(cell.getProductId()));
            cellDTO.setPrice(product.getPrice());
            cellDTO.setDiscountPrice(product.getDiscountPrice());
            cellList.add(cellDTO);
        }
        sellProductDTO.setCellList(cellList);
        dispenseNotice(NoticeTypes.SELL_PRODUCT.getCode(), JsonUtil.toJsonString(sellProductDTO), LoginTypeEnum.STAFF.name(), CabinetCache.getCabinet(order.getChipImei()).getBelongId());
    }

    @Subscribe
    public void ChangePriceNoticeEvent(ChangePriceNoticeEvent event){
        List<Long> belongIds = event.getBelongIds();
        Long productId = event.getProductId();
        LoginInfo loginInfo = event.getLoginInfo();
        List<BelongDO> belongDOList = belongService.listByIds(belongIds);

        ChangePriceDTO changePriceDTO = new ChangePriceDTO();
        changePriceDTO.setNoticeType(CHANGE_PRICE.getText());
        changePriceDTO.setNoticeTitle(CHANGE_PRICE.getTitle());
        changePriceDTO.setNoticeContent(StringUtils.format(NoticeTypes.CHANGE_PRICE.getTemplate(),ProductCache.getProductName(productId)));

        Long noticeId = noticeService.save(new NoticeDO(MessageTypes.NOTICE.getCode(),NoticeTypes.CHANGE_PRICE.getCode(),
                NoticeTypes.getTitle(CHANGE_PRICE.getCode()),JsonUtil.toJsonString(changePriceDTO), loginInfo.getLoginType().name()));
        ArrayList<NoticeUserDO> list = new ArrayList<>();
        for (BelongDO belongDO : belongDOList) {
            NoticeUserDO noticeUserDO = new NoticeUserDO();
            noticeUserDO.setUserType(belongDO.getBelongType());
            noticeUserDO.setUserId(belongDO.getUserId());
            noticeUserDO.setNoticeId(noticeId);
            list.add(noticeUserDO);
        }
        NoticeUserDO noticeUserDO = new NoticeUserDO(UserType.PLATE.getCode(), 1L, noticeId);
        list.add(noticeUserDO);
        noticeUserService.saveBatch(list);
    }

    @Subscribe
    public void captureProductNoticeEvent(CaptureProductNoticeEvent event) {
        Long containerId = event.getContainerId();
        Integer cargoNums = event.getCargoNums();
        LoginInfo user = event.getLoginInfo();
        //找到有商品的格子
        List<ContainerCell> cells = cabinetCellService.search(CabinetCellListQueryBO.builder().containerId(containerId).build());

        ContainerDO cabinet = cabinetService.getById(containerId);

        Assert.isTrue(BeanUtils.isNotNull(cells), "找不到货柜商品信息");

        //找到货柜所在的站点信息
        CabinetSiteDO containerSite = new CabinetSiteDO();
        containerSite.setContainerId(cabinet.getContainerId());
        SiteDO site = cabinetService.getSiteByCid(cabinet.getContainerId());
        Assert.isTrue(BeanUtils.isNotNull(site), "找不到货柜站点信息");

        CaptureProductDTO captureProductDTO = new CaptureProductDTO();
        List<NoticeDataCellDTO> cellList = new ArrayList<>();
        captureProductDTO.setChipImei(cabinet.getChipImei());
        captureProductDTO.setContainerId(containerId);
        captureProductDTO.setContainerName(cabinet.getContainerName());
        captureProductDTO.setSiteId(site.getId());
        captureProductDTO.setSiteName(site.getSiteName());
        captureProductDTO.setLocationId(cabinet.getLocationId());
        captureProductDTO.setLocationName(BaseCache.getSiteLocationName(cabinet.getLocationId()));
        captureProductDTO.setNoticeTitle(CAPTURE_PRODUCT.getTitle());
        captureProductDTO.setNoticeContent(StringUtils.format(CAPTURE_PRODUCT.getTemplate(), ProductCache.getProductName(cells.get(0).getProductId()), cargoNums));

        //系统补货通知
        Integer emptyCellNums = 0;
        for (ContainerCell cell : cells) {
            NoticeDataCellDTO cellDTO = new NoticeDataCellDTO();
            BeanUtils.clone(cell, cellDTO);
            ProductCacheDTO product = ProductCache.getProduct(cell.getProductId());
            cellDTO.setAlbumPics(product.getAlbumPics());
            cellDTO.setProductName(ProductCache.getProductName(cell.getProductId()));
            cellDTO.setPrice(product.getPrice());
            cellDTO.setDiscountPrice(product.getDiscountPrice());
            emptyCellNums += emptyCellNums + (cell.getCeilingQuantity() - cell.getProductQuantity());
            cellList.add(cellDTO);
        }
        captureProductDTO.setEmptyCellNums(emptyCellNums);
        captureProductDTO.setCellList(cellList);

        dispenseNotice(NoticeTypes.CAPTURE_PRODUCT.getCode(), JsonUtil.toJsonString(captureProductDTO), LoginTypeEnum.STAFF.name(),user.getBelongId());

        //获取员工实时信息
        StaffDO response = staffService.select(user.getUserId());

        StaffDO update = new StaffDO();
        update.setId(user.getUserId());
        update.setFillCargoCount(response.getFillCargoCount() + 1);
        Assert.isTrue(staffService.update(update), "更新失败");
    }

    private void AbnormalDeviceNotice(AbnormalDeviceNoticeEvent event){
        Long containerId = event.getContainerId();

        ContainerDO cabinet = cabinetService.getById(containerId);

        NoCargoDTO noCargoDTO = new NoCargoDTO();
        noCargoDTO.setNoticeType(NO_CARGO.getText());
        noCargoDTO.setNoticeTitle(NO_CARGO.getTitle());
        noCargoDTO.setNoticeContent(StringUtils.format(NO_CARGO.getTemplate(),BaseCache.getSiteName(cabinet.getSiteId()),cabinet.getContainerName()));

        dispenseNotice(NO_CARGO.getCode(), JsonUtil.toJsonString(noCargoDTO),LoginTypeEnum.CUSTOMER.name(), cabinet.getBelongId());
    }

    /**
     *
     * @param noticeType 消息类型
     * @param content   消息类容
     * @param loginType 发消息人的类型
     * @param belongId  接收消息的主体belongId
     */
    private void dispenseNotice(Integer noticeType, String content,String loginType,Long belongId){
        Long noticeId = noticeService.save(new NoticeDO(MessageTypes.NOTICE.getCode(),noticeType,NoticeTypes.getTitle(noticeType), content, loginType));
        ArrayList<NoticeUserDO> list = new ArrayList<>();
        // 可读 登录用户类型
        List<String> readRangeTypes = NoticeTypes.getReadRangeTypes(noticeType);
        Map<String, List<Long>> map = handleUserId(belongId);
        for (String readRangeType : readRangeTypes) {
            if (UserType.PLATE.getCode().equals(readRangeType)) {
                NoticeUserDO noticeUserDO = new NoticeUserDO(readRangeType, 1L, noticeId);
                list.add(noticeUserDO);
            } else if (UserType.AGENT.getCode().equals(readRangeType)) {
                List<Long> agentIds = map.containsKey(UserType.AGENT.getCode()) ? map.get(UserType.AGENT.getCode()) : new ArrayList<>();
                for (Long agentId : agentIds) {
                    NoticeUserDO noticeUserDO = new NoticeUserDO(readRangeType, agentId, noticeId);
                    list.add(noticeUserDO);
                }
            } else if (UserType.SITE.getCode().equals(readRangeType)) {
                List<Long> siteIds = map.containsKey(UserType.SITE.getCode()) ? map.get(UserType.SITE.getCode()) : new ArrayList<>();
                for (Long siteId : siteIds) {
                    NoticeUserDO noticeUserDO = new NoticeUserDO(readRangeType, siteId, noticeId);
                    list.add(noticeUserDO);
                }
            } else if (UserType.STAFF.getCode().equals(readRangeType)) {
                List<Long> staffIds = map.containsKey(UserType.STAFF.getCode()) ? map.get(UserType.STAFF.getCode()) : new ArrayList<>();
                for (Long staffId : staffIds) {
                    NoticeUserDO noticeUserDO = new NoticeUserDO(readRangeType, staffId, noticeId);
                    list.add(noticeUserDO);
                }
            }
        }
        noticeUserService.saveBatch(list);
    }

//    private Map<String,List<Long>> getUserId(String loginType,Long belongId){
//        Map<String,List<Long>> map = new HashMap<>();
//        BelongDO belong = BaseCache.getBelong(belongId);
//        if (BeanUtils.equals(loginType,LoginTypeEnum.STAFF.name(),LoginTypeEnum.CUSTOMER.name())) {
//            Long siteId = belong.getSiteId();
//            List<Long> staffIds = ConvertDataUtil.list2FieldList(staffService.listByManagerId(siteId), StaffDO::getId);
//            map.put(UserType.STAFF.getCode(), staffIds);
//        }else {
//            List<BelongDO> siteBelongs = belongService.listByPid(UserType.SITE.getCode(), belong.getParentId());
//            BelongDO agentBelong = BaseCache.getBelong(belong.getParentId());
//
//            List<Long> userIds = ConvertDataUtil.list2FieldList(siteBelongs, BelongDO::getUserId);
//            map.put(UserType.SITE.getCode(), userIds);
//
//            map.put(UserType.AGENT.getCode(), Lists.newArrayList(agentBelong.getUserId()));
//        }
//        return map;
//    }


    private Map<String,List<Long>> handleUserId(Long belongId) {
        Map<String, List<Long>> map = new HashMap<>();
        BelongDO belong = BaseCache.getBelong(belongId);

        if (UserType.SITE.getCode().equals(belong.getBelongType())){
            Long siteId = belong.getSiteId();
            List<Long> staffIds = ConvertDataUtil.list2FieldList(staffService.listByManagerId(siteId), StaffDO::getId);
            map.put(UserType.STAFF.getCode(), staffIds);
        }
        List<BelongDO> siteBelongs = belongService.listByPid(UserType.SITE.getCode(), belong.getParentId());
        BelongDO agentBelong = BaseCache.getBelong(belong.getParentId());

        List<Long> userIds = ConvertDataUtil.list2FieldList(siteBelongs, BelongDO::getUserId);
        map.put(UserType.SITE.getCode(), userIds);
        map.put(UserType.AGENT.getCode(), Lists.newArrayList(agentBelong.getUserId()));

        return map;
    }


}
